{***************************************************************************}
{                                                                           }
{           Spring Framework for Delphi                                     }
{                                                                           }
{           Copyright (C) 2009-2011 DevJET                                  }
{                                                                           }
{           http://www.spring4d.org                                         }
{                                                                           }
{***************************************************************************}
{                                                                           }
{  Licensed under the Apache License, Version 2.0 (the "License");          }
{  you may not use this file except in compliance with the License.         }
{  You may obtain a copy of the License at                                  }
{                                                                           }
{      http://www.apache.org/licenses/LICENSE-2.0                           }
{                                                                           }
{  Unless required by applicable law or agreed to in writing, software      }
{  distributed under the License is distributed on an "AS IS" BASIS,        }
{  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. }
{  See the License for the specific language governing permissions and      }
{  limitations under the License.                                           }
{                                                                           }
{***************************************************************************}

unit Spring.Serialization.Backend.SuperObject;

{$I Spring.inc}

interface
uses
  SuperObject,
  Classes,
  SysUtils,
  Rtti,
  Generics.Collections,
  Variants,
  Spring,
  Spring.Collections,
  Spring.Serialization.Backend;

type
  TXmlBackend_SuperObject = class(TBackendBase, IBackend, IInterface)
  protected
    procedure ContentToTree(const stream: TStream; const document: IBackendDocument); override;
    procedure TreeToContent(const stream: TStream; const document: IBackendDocument); override;
  end;

implementation

uses
  Spring.Serialization,
  Spring.Serialization.ResourceStrings;

{ TXmlBackend_SuperObject }

procedure TXmlBackend_SuperObject.TreeToContent(const stream: TStream;
  const document: IBackendDocument);

  procedure NodeToSuperObject(const node: IBackendNode; const superObject: ISuperObject);
  var
    attributeName: string;
    child: IBackendNode;
  begin
    if superObject.IsType(stObject) then
    begin
      for attributeName in node.Attributes.Keys do
        superObject.AsObject.S[attributeName] := node.Attributes.Items[attributeName];

      if node.Children.IsEmpty then
        if node.NodeValue <> '' then
          superObject.AsObject.S[CNodeValueAttributeName] := node.NodeValue
        else
      else
        for child in node.Children do
        begin
          if child.NodeName = CItemsCollectionCodeName then
            superObject.AsObject.O[child.NodeName] := TSuperObject.Create(stArray)
          else
            superObject.AsObject.O[child.NodeName] := TSuperObject.Create;

          NodeToSuperObject(child, superObject.AsObject.O[child.NodeName]);
        end;
    end
    else
      if superObject.IsType(stArray) then
        for child in node.Children do
          NodeToSuperObject(child, superObject.AsArray[superObject.AsArray.Add(TSuperObject.Create)])
      else
        raise Exception.Create('Error Messagex ' + IntToStr(Ord(superObject.DataType)));
  end;

var
  fSuperObject: ISuperObject;
begin
  fSuperObject := TSuperObject.Create;
  NodeToSuperObject(document.Root.Children.First, fSuperObject);

  fSuperObject.SaveTo(stream, true, true);
end;

procedure TXmlBackend_SuperObject.ContentToTree(const stream: TStream;
  const document: IBackendDocument);

  procedure SuperObjectToNode(const superObject: ISuperObject; const node: IBackendNode);
  var
    i: integer;
    newNode1, newNode2: IBackendNode;
    item: TSuperAvlEntry;
  begin
    if superObject.IsType(stObject) then
      for item in superObject.AsObject do
        if item.Value.IsType(stObject) or item.Value.IsType(stArray) then
        begin
          newNode1 := node.AddChild;
          newNode1.NodeName := item.Name;
          SuperObjectToNode(item.Value, newNode1);
        end
        else
          if item.Name = CNodeValueAttributeName then
            node.NodeValue := item.Value.AsString
          else
            node.Attributes.AddOrSetValue(item.Name, item.Value.AsString);


    if superObject.IsType(stArray) then
      for i := 0 to superObject.AsArray.Length - 1 do
        if superObject.AsArray[i].IsType(stObject) then
        begin
          newNode2 := node.AddChild;
          newNode2.NodeName := CItemCollectionCodeName;
          SuperObjectToNode(superObject.AsArray[i], newNode2);
        end;
  end;

var
  fSuperObject: ISuperObject;
  node: IBackendNode;
begin
  document.Root.Clear;
  try
    fSuperObject := TSuperObject.ParseStream(stream, true);
  except
    raise ESerializationSourceCodeException.CreateRes(@SCodeNotFound);
  end;
  node := document.Root.AddChild;
  node.NodeName := CInstanceCollectionCodeName;
  SuperObjectToNode(fSuperObject, node);
end;

end.
